import { Provide,Inject,FORMAT,Task} from '@midwayjs/decorator';
import { DBBase } from '../base/DBBase';
import { WechatPaySDK } from '../base/WechatSDK';
import { ErrCode } from '../common/ErrCode';
import { Tools } from '../common/Tools';
import { PaidOrder } from '../entity/paid.entity';
import { IBaseConfig, IRechargeDiscountsItem, SystemConfigType } from '../interfaces/ISystem.interface';
import { IJsapiClientPay, IPlaceJSAPI, IWechatConfigItem, IWechatErrResult, IWechatQueryResponse, WechatTradeState } from '../interfaces/IWechat.interface';
import { SystemConfigService } from './system.service';
import { UserService } from './user.service';
import { Repository } from "typeorm";
// import { UserPartner } from '../entity/userPartner.entity';
import { UserPartnerStatus } from '../interfaces/IPartner.interface';
import { PartnerService } from './partner.service';
import { RedisService } from '@midwayjs/redis';
import { CurrencyLog } from '../entity/CurrencyLog.entity';
import { CurrencyLogStatus, CurrencyLogType } from '../interfaces/IUser.interface';
// import { IReturnData } from '../interfaces/IBase.interface';

@Provide()
export class PayService extends DBBase{
    /**证书路劲 */
    private privateKeyPath:string = "../../certificate/apiclient_key.pem";
    private wechatConfig:IWechatConfigItem = {
        appid:"wxe918beb29b2be698",
        secret:"63e79b77a801f482ed808bdfe0a6e782",

        mid:"1490907382",
        secretV2:"ef3ba8726fe10e91a12b0d82e31c5119",
        secretV3:"b6385e0d527d7b6e8dc239b25593074c",
        apiclient_cert_no:"4E464B3E7E376A6FE7C561DAD525B559C59C3EFD",
    }
    @Inject()
    systemConfig:SystemConfigService;

    @Inject()
    userService:UserService;

    @Inject()
    partnerService:PartnerService;

    @Inject()
    redisService:RedisService;

    private async initConfig():Promise<IWechatConfigItem>{
        this.wechatConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Wechat_Config);
        return this.wechatConfig;
    }

    @Task({
        repeat: { cron: FORMAT.CRONTAB.EVERY_PER_5_SECOND}
    })
    public async queryTask(){
        let rechargelist:CurrencyLog[] = await this.getRechargeLog(CurrencyLogStatus.Ongoing);
        if(rechargelist != null){
            if(rechargelist.length > 0){
                for(let i in rechargelist){
                    this.queryPay(rechargelist[i].append);
                }
            }
        }
    }
    private async addPaidInfo(ordersn:string,userid:number,openid:string,partnerid:number,price):Promise<string>{
        let order:Repository<PaidOrder> = await this.Repository({entities:PaidOrder});
        let neworder:PaidOrder = await order.findOne({where:{ordersn:ordersn}});
        if(neworder == null){
            neworder = new PaidOrder();
            neworder.ordersn = ordersn;
            neworder.status = WechatTradeState.NOTPAY;
            neworder.addtime = Tools.timestamp;
            neworder.userid = userid;
            neworder.openid = openid;
            neworder.partnerId = partnerid;
            neworder.price = price;
            await order.insert(neworder);
            return ordersn;
        }else{
            return await this.addPaidInfo(Tools.makeNumberId(32),userid,openid,partnerid,price);
        }
    }

    public async updatePaidInfo(Result:IWechatQueryResponse):Promise<ErrCode>{
        let order:Repository<PaidOrder> = await this.Repository({entities:PaidOrder});
        let neworder:PaidOrder = await order.findOne({where:{ordersn:Result.out_trade_no}});
        if(neworder == null){
            return ErrCode.SYSTEM_FAIL;
        }
        switch(Result.trade_state){
            case WechatTradeState.CLOSED:
                neworder.status = WechatTradeState.CLOSED;
                neworder.lasttime = Tools.timestamp;
                break;
            case WechatTradeState.SUCCESS:
                neworder.status = WechatTradeState.SUCCESS;
                neworder.lasttime = Tools.timestamp;
                neworder.price = Result.amount.total;
                neworder.paytime = Tools.DateToTimestamp(Result.success_time);
                neworder.openid = Result.payer.openid;
                neworder.transaction_id = Result.transaction_id;
                await this.partnerService.updateUserPartnerStatus([neworder.userid],neworder.partnerId,UserPartnerStatus.Paid,UserPartnerStatus.Wait_Paid);
                // 更新合伙币
                let config:IBaseConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Base_Config);
                await this.userService.AddCurrency([neworder.userid],(neworder.price * config.Recharge_base_ratio));
                //操作

                break;
            case WechatTradeState.NOTPAY:
                return ErrCode.SYSTEM_SUCCESS;
        }
        try {
            await order.save(neworder);
            return ErrCode.SYSTEM_SUCCESS;
        } catch (error) {
            console.error(error);
            return ErrCode.SYSTEM_FAIL;
        }
    }
    
    public async paid(userid:number,partnerid:number,price:number,partnerName:string):Promise<IJsapiClientPay|IWechatErrResult|ErrCode>{
        this.wechatConfig = await this.initConfig();
        if(this.wechatConfig != null){
            let sdk = WechatPaySDK.init(this.wechatConfig,this.privateKeyPath);
            let openid = await this.userService.getUserOpenid(userid);
            let ordersn = await this.addPaidInfo(Tools.makeNumberId(32),userid,openid as string,partnerid,price);
            if(openid != ErrCode.USER_NOT_FOUND_OPENID){
                let order:IPlaceJSAPI = {
                    description:"参加项目购:"+partnerName,
                    out_trade_no:ordersn,
                    notify_url:"",
                    amount:{ total:Tools.formatMoney(price)},
                    payer:{openid:openid as string},
                    time_expire:Tools.formattime((Tools.timestamp+(10*60)),'yyyy-MM-ddTHH:mm:ss')+'+08:00'
                }
                let payconfig = await sdk.jsapi(order);
                return payconfig;
            }else{
                return openid;
            }
        }else{
            return ErrCode.SYSTEM_CONFIG_NULL;
        }
    }

    public async getRechargeDiscountsList():Promise<any>{
       let base:IBaseConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Base_Config);
       if(base != null){
        return Tools.formatData(base.Recharge_discounts_list);
       }
       return ErrCode.SYSTEM_CONFIG_NULL;
    }
    /**获取充值金额对应的合伙点数 */
    public async getRechargeCurrency(price:number):Promise<number>{
        let base:IBaseConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Base_Config);
        let discountsList:IRechargeDiscountsItem[] = base.Recharge_discounts_list;
        let list = discountsList.filter((item)=>{
            return parseFloat(item.price+'')%price == 0;
        })
        if(list.length > 0){//符合优惠价格
            return parseFloat(list[0].currency+'');
        }
        return parseFloat(base.Recharge_base_ratio+'') * price;
    }

    public async Recharge(userid:number,price:number):Promise<IJsapiClientPay|IWechatErrResult|ErrCode>{
        this.wechatConfig = await this.initConfig();
        if(this.wechatConfig != null){
            this.wechatConfig.appid = this.wechatConfig.smallAppid;
            let sdk = WechatPaySDK.init(this.wechatConfig,this.privateKeyPath);
            let openid = await this.userService.getUserOpenid(userid);
            let ordersn = Tools.makeNumberId(32);
            if(openid != ErrCode.USER_NOT_FOUND){
                let order:IPlaceJSAPI = {
                    description:"充值",
                    out_trade_no:ordersn,
                    notify_url:"",
                    amount:{ total:Tools.formatMoney(price)},
                    payer:{openid:openid as string},
                    time_expire:Tools.formattime((Tools.timestamp+(10*60)),'yyyy-MM-ddTHH:mm:ss')+'+08:00'
                }
                let payconfig:IJsapiClientPay|IWechatErrResult = await sdk.jsapi(order);
                if((payconfig as IJsapiClientPay).appId != null){
                    await this.AddRechargeLog(userid,ordersn,price);
                    return payconfig;
                }else{
                    return (payconfig as IWechatErrResult);
                }
            }else{
                return openid;
            }
        }
        return ErrCode.SYSTEM_CONFIG_NULL;
    }
    /**获取充值未完成的记录 */
    public async getRechargeLog(status:CurrencyLogStatus):Promise<CurrencyLog[]>{
        let rep:Repository<CurrencyLog> = await this.Repository({entities:CurrencyLog});
        let list:CurrencyLog[] = await rep.find({where:{status:status,type:CurrencyLogType.Recharge}});
        return list;
    }
    /**更新重新记录状态 */
    public async UpdateRechargeLog(tradeNo:string,status:CurrencyLogStatus =CurrencyLogStatus.Sucdess):Promise<ErrCode>{
        let rep:Repository<CurrencyLog> = await this.Repository({entities:CurrencyLog});
        let log:CurrencyLog = await rep.findOne({where:{append:tradeNo}});
        if(log != null){
            log.status = status;
            try {
                await rep.save(log);
                  //更新用户合伙点数
                if(status == CurrencyLogStatus.Sucdess){
                    await this.userService.AddCurrency([log.userid],log.currency);
                    //如果，有等待付款的项目。则扣除对于的合伙点数
                }
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.SYSTEM_FAIL;
        }
    }
    /**添加充值记录 */
    public async AddRechargeLog(userid:number,tradeNo:string,price:number):Promise<ErrCode>{
        let rep:Repository<CurrencyLog> = await this.Repository({entities:CurrencyLog});
        if(rep){
            let log:CurrencyLog = new CurrencyLog();
            log.currency = await this.getRechargeCurrency(price);
            log.addtime = Tools.timestamp;
            log.status = CurrencyLogStatus.Ongoing;
            log.type = CurrencyLogType.Recharge;
            log.userid = userid;
            log.append = tradeNo;
            log.remark = "充值:"+price+"元"
            try {
                await rep.save(log);
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.SYSTEM_FAIL;
        }
    }

    public async queryPay(ordersn:string = null):Promise<IWechatQueryResponse>{
        let querorder:string = ordersn;
        let wechatConfig:IWechatConfigItem = await this.initConfig();
        let sdk = WechatPaySDK.init(wechatConfig,this.privateKeyPath);
        let queryResult:IWechatQueryResponse = await sdk.PayQuery(querorder);
        this.updatePaidInfo(queryResult);//更新，自己参加的项目信息
      
        switch(queryResult.trade_state){
            case WechatTradeState.CLOSED:
                this.UpdateRechargeLog(ordersn,CurrencyLogStatus.Fail);
                break;
            case WechatTradeState.SUCCESS:
                this.UpdateRechargeLog(ordersn);
                break;
            case WechatTradeState.NOTPAY:
                break;
        }
        return queryResult;
    }
    /**
     *
     *
     * @param {string} ordersn
     * @param {number} price 
     * @param {string} reason 退款原因
     * @return {*}  {Promise<any>}
     * @memberof PayService
     */
    public async refund(ordersn:string,price:number,reason:string):Promise<any>{
        let orderRep:Repository<PaidOrder> = await this.Repository({entities:PaidOrder});
        let order:PaidOrder = await orderRep.findOne({select:['price','status'],where:{ordersn:ordersn,status:WechatTradeState.SUCCESS}});
        if(order.price > 0 && order.status == WechatTradeState.SUCCESS){
            // let wechatConfig:IWechatConfigItem = await this.systemConfig.getSystemConfig(SystemConfigType.Pay_wechat);
            // let sdk = WechatPaySDK.init(wechatConfig,this.privateKeyPath);
            // let rdata:IWechatRefundReq = {
            //     out_trade_no:ordersn,
            //     reason:reason,
            //     amount:{
            //         total:order.price,
            //         refund:price,
            //         currency:"CNY"
            //     }
            // }
            // let result = await sdk.Refund(rdata);
            //检查退款信息
        }else{
            return ErrCode.SYSTEM_FAIL;
        }
    }
    // private async reFundQuery():Promise<any>{

    // }
}